;;;;;;;;;;;;;;;
; ACTOR TESTS ;
;;;;;;;;;;;;;;;

; TEST 03
#|
(defclass chat (remote-object)
  ((username :initarg :username :accessor chat-username)))
(defmethod receive-text ((receiver chat) sender text)
  (when-resolved  (send sender (chat-username sender))
                  (lambda (username)
                    (format *screen-output* "~D says: ~D~%" username text))))

(start-communication *communication-actor*)
(start-discovery *discovery-actor*)
|#

#| Peer 1
(defvar *cheo-chat* (make-instance 'chat :username "Cheo"))
(defvar *buddy-chat* (import-service "chat"))
(send *buddy-chat* (receive-text *buddy-chat* *cheo-chat* "hi, buddy!"))
|#

#| Peer 2
(defvar *jorge-chat* (make-instance 'chat :username "Jorge"))
(publish-service *jorge-chat* "chat")
|#

; TEST 04
#|
(defclass chat (remote-object)
  ((username :initarg :username :accessor chat-username)))
(defmethod receive-text ((receiver chat) sender text)
  (when-resolved  (send sender (chat-username sender))
                  (lambda (username)
                    (format *screen-output* "~D says: ~D~%" username text))))

(start-communication *communication-actor*)
(start-network)
; Peer 1
(defvar *cheo-chat* (make-instance 'chat :username "Cheo"))
(defvar *buddy-chat* (import-service "_p2pchat._tcp."))
; Peer 2
(defvar *jorge-chat* (make-instance 'chat :username "Jorge"))
|#
#| Peer 1
(when-discovered *buddy-chat*
                 (lambda (buddy)
                   (send buddy (receive-text buddy *cheo-chat* "hi, buddy!") nil)
                   (when-disconnected buddy
                                      (lambda (buddy)
                                        (format *screen-output* "buddy disconnected~%")))
                   (when-reconnected buddy
                                     (lambda (buddy)
                                       (format *screen-output* "buddy reconnected~%")))))
|#

#| Peer 2
(publish-service *jorge-chat* "_p2pchat._tcp.")
|#

#| Peer 1
(send *buddy-chat* (receive-text *buddy-chat* *cheo-chat* "hi, connected buddy!") nil)
|#

#| Peer 2
(stop-network)
;(cancel-service *jorge-chat* "_p2pchat._tcp.")
|#

#| Peer 1
(send *buddy-chat* (receive-text *buddy-chat* *cheo-chat* "hi, reconnected buddy!") nil)
|#

#| Peer 2
(start-network)
;(publish-service *jorge-chat* "_p2pchat._tcp.")
|#

; TEST 05
#|
(defclass chat (remote-object)
  ((username :initarg :username :accessor chat-username)))
(defmethod receive-text ((receiver chat) sender text)
  (when-resolved  (send sender (chat-username sender))
                  (lambda (username)
                    (format *screen-output* "~D to ~D: ~D~%" username (chat-username receiver) text))))

(start-communication *communication-actor*)
(start-network)
; Peer 1
(defvar *bob-chat* (make-instance 'chat :username "Bob"))
|#

; Other Peers
;(defvar *alice-chat* (make-instance 'chat :username "Alice"))
;(defvar *ray-chat* (make-instance 'chat :username "Ray"))
;(defvar *tom-chat* (make-instance 'chat :username "Tom"))


#| Peer 1
(whenever-discovered "_p2pchat._tcp."
                     (lambda (buddy)
                       (send buddy (receive-text buddy *bob-chat* "hi, buddy!") nil)
                       (when-disconnected buddy
                                          (lambda (buddy)
                                            (format *screen-output* "buddy disconnected~%")))
                       (when-reconnected buddy
                                         (lambda (buddy)
                                           (format *screen-output* "buddy reconnected~%")))))
|#

#| Other peers
(publish-service *alice-chat* "_p2pchat._tcp.")
(publish-service *ray-chat* "_p2pchat._tcp.")
(publish-service *tom-chat* "_p2pchat._tcp.")
|#

#| Peer 1
(send *alice-chat* (receive-text *buddy-chat* *cheo-chat* "hi, connected buddy!") nil)
|#

#| Other peers
(stop-network)
|#

#| Peer 1
(send *alice-chat* (receive-text *buddy-chat* *cheo-chat* "hi, reconnected buddy!") nil)
|#

#| Other peers
(start-network)
|#

; TEST 06

#|
; text-message
(defstruct text-message from content)

; Local facade
(defclass im-local-facade (remote-object)
  ((username :initarg :username :accessor im-local-facade-username)
   (buddies :initarg :buddies :accessor im-local-facade-buddies)))

(defmethod talk (local-facade to text)
    (let ((buddy (gethash to (im-local-facade-buddies local-facade))))
      (if buddy
          (let ((message (make-text-message :from (im-local-facade-username local-facade) :content text)))
            (send buddy (receive buddy message))
            (format *screen-output* "~D sent to ~D" text to))
        (format *screen-output* "unknown body:~D" to))))

; Remote facade
(defclass im-remote-facade (remote-object)
  ((username :initarg :username :accessor im-remote-facade-username)))

(defmethod receive (remote-facade message)
    (format *screen-output* "~D: ~D" (text-message-from message) (text-message-content message)))

(defmethod get-username ((remote-facade im-remote-facade))
  (send remote-facade (im-remote-facade-username remote-facade)))

(defun create-instant-messenger (username)
  (let* ((buddies (make-hash-table :test #'equal))
        (local-facade (make-instance 'im-local-facade :username username :buddies buddies))
        (remote-facade (make-instance 'im-remote-facade :username username))
        (instant-messenger "_p2pchat._tcp."))
    (make-actor instant-messenger local-facade remote-facade)
    (publish-service remote-facade instant-messenger)

    (whenever-discovered instant-messenger
                     (lambda (messenger)
                       (when-resolved (send messenger (im-remote-facade-name messenger))
                                      (lambda (name)
                                        (unless (or (gethash name buddies)
                                                    (equal name (im-local-facade-username local-facade)))
                                          (setf (gethash name buddies) name)
                                          (format *screen-output* "~D added to your buddy list" name)
                                          (when-disconnected messenger
                                                             (lambda (messenger)
                                                               (format *screen-output* "~D offline!" name)))
                                          (when-reconnected messenger
                                                            (lambda (messenger)
                                                              (format *screen-output* "~D online!" name))))))))
    local-facade))

(start-communication *communication-actor*)
(start-discovery *discovery-actor*)
|#

#| Peer 1
(defvar *bob-im* (create-instant-messenger "Bob"))
(talk *bob-im* "Alice" "Hi, Alice")
;(send *bob-im* (talk *bob-im* "Alice" "Hi, Alice"))
|#

#| Peer 2
(defvar *alice-im* (create-instant-messenger "Alice"))
(talk *alice-im* "Bob" "Hi, Bob")
|#

#| Peer 1
(talk *bob-im* "Alice" "how are you?")
|#

#| Peer 2
(stop-network)
|#

#| Peer 1
(talk *bob-im* "Alice" "Ok, you went offline. Anyway, I didn't want to talk to you.")
|#

#| Peer 2
(start-network)
|#


